<template>
  <div id="app">
    <h1>ASR 测试客户端</h1>
    <div class="status-bar">
      <span v-if="error" class="error-message">{{ error }}</span>
    </div>
    
    <div class="mode-selector">
      <button 
        @click="selectMode('realtime')"
      >
        实时语音识别
      </button>
      <button 
        @click="selectMode('file')"
      >
        文件上传识别
      </button>
    </div>

    <div v-if="mode === 'realtime'" class="realtime-mode">
      <button @click="toggleRecording">{{ isRecording ? '停止录音' : '开始录音' }}</button>
      <div class="result-display">
        <h3>识别结果:</h3>
        <p>{{ recognitionResult }}</p>
      </div>
    </div>

    <div v-else-if="mode === 'file'" class="file-mode">
      <input type="file" accept="audio/*" @change="handleFileUpload" />
      <div class="result-display">
        <h3>识别结果:</h3>
        <p>{{ recognitionResult }}</p>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      mode: null,
      isRecording: false,
      recognitionResult: '',
      mediaRecorder: null,
      audioChunks: [],
      error: null,
      audioStream: null
    }
  },
  beforeUnmount() {
    this.stopRecording();
  },
  methods: {
    async selectMode(mode) {
      this.mode = mode;

      try {
        const response = await fetch('/api/select-mode', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
              mode: mode
            })
        });
      }
      catch(err) {
        console.log("Selecting mode failed:"+err);
      }

      if('realtime' === mode) {
        let sampleRate = 16000;
        await navigator.mediaDevices.getUserMedia({ audio: true })
        .then(stream => {
          // 创建AudioContext分析音频流
          const audioContext = new AudioContext();
          const source = audioContext.createMediaStreamSource(stream);
          
          // 获取采样率
          sampleRate = audioContext.sampleRate;
          console.log('当前采样率:', sampleRate + 'Hz');
          
          // 创建MediaRecorder
          const mediaRecorder = new MediaRecorder(stream);
          
          // 使用采样率进行后续操作...
        })
        .catch(error => {
          console.error('获取媒体设备失败:', error);
        });

        console.log("sampleRate to set:"+sampleRate);
        try {
          const setAudioParams_response = await fetch('/api/set-audio-params', {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json'
            },
            body: JSON.stringify({
              sample_rate: sampleRate,
              bit_depth: 16,
              num_channels: 1
            })
          });
        }
        catch(err) {
          console.log("Setting audio params failed:"+err);
        }
      }
    },
    toggleRecording() {
      if (!this.isRecording) {
        this.startRecording();
      } else {
        this.stopRecording();
      }
    },
    
    async startRecording() {
    /*  OpenAI-Whisper要求使用以下音频规格：
    #     channelCount: 1,
    #     bitDepth: 16,
    #     sampleRate: 16000,
    #     bitrate: 256000
    #*/

      try {
        this.error = null;
/*        const audio_constraints = {
            audio: {
              channelCount: 1,
              sampleRate: 16000
//              bitrate: 256000
            },
            video: false
        };*/
        const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
        //const stream = await navigator.mediaDevices.getUserMedia(audio_constraints);
        this.audioStream = stream;


        this.mediaRecorder = new MediaRecorder(stream);
        this.audioChunks = [];

        this.mediaRecorder.ondataavailable = (event) => {
          console.log("some audio recorded!");
          console.log("MediaRecorder mimeType:", this.mediaRecorder.mimeType);
          console.log("Audio chunk size:", event.data.size, "bytes");
          this.audioChunks.push(event.data);
          //const audioBlob = new Blob(this.audioChunks, { type: 'audio/wav' });
          const audioBlob = new Blob(this.audioChunks, { type: this.mediaRecorder.mimeType });
          this.sendAudioChunk(audioBlob);
        };
        
        this.mediaRecorder.onerror = (event) => {
          this.error = 'Recording error: ' + event.error.name;
          this.stopRecording();
        };
        
        this.mediaRecorder.start(5500); // 每<6秒发送一次
        this.isRecording = true;
      } catch (error) {
        this.error = '无法访问麦克风: ' + error.message;
        console.error('录音失败:', error);
      }
    },
    stopRecording() {
      if (this.mediaRecorder && this.mediaRecorder.state !== 'inactive') {
        this.mediaRecorder.stop();
      }
      if (this.audioStream) {
        this.audioStream.getTracks().forEach(track => track.stop());
        this.audioStream = null;
      }
      this.isRecording = false;
      this.audioChunks = [];
    },
    async sendAudioChunk(audioBlob) {
      console.log("audioBlob size:", audioBlob.size, "type:", audioBlob.type);
      const reader = new FileReader();
      reader.onload = async () => {

        console.log("DataFromReader[0]:"+reader.result.split(',')[0]);
        const base64data = reader.result.split(',')[1];
        
        // 调试：检查 base64 数据
        console.log("Base64 length:", base64data.length);
        console.log("Base64 first 50 chars:", base64data.substring(0, 50));
        console.log("Base64 last 10 chars:", base64data.substring(base64data.length - 10));
        
        // 检查是否包含非法字符
        const hasInvalidChars = /[^A-Za-z0-9+/=]/.test(base64data);
        if (hasInvalidChars) {
          console.error("Base64 contains invalid characters!");
        }
        
        try {
          const response = await fetch('/api/runASR-audioSegment', {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json'
            },
            body: JSON.stringify({
              type: 'audio_chunk',
              audio: base64data
            })
          });
          const data = await response.json();
          if (data.text) {
            this.recognitionResult = data.text;
          }
        } catch (err) {
          this.error = 'Failed to send audio chunk';
          console.error(err);
        }
      };
      reader.readAsDataURL(audioBlob);
    },
    async handleFileUpload(event) {
      const file = event.target.files[0];
      const reader = new FileReader();
      
      reader.onload = async () => {
        //return; //Error disappeared!
        console.log("onload upload-file");
        const base64data = reader.result.split(',')[1];
        console.log("File base64data:"+base64data); // OK
        try {
//          const response = await fetch('/api/upload-file', {
          const response = await fetch('/api/runASR-uploadFile', {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json'
            },
            body: JSON.stringify({
              type: 'file_upload',
              file_data: base64data,
              filename: file.name
            })
          });
          console.log("OK1");
          const data = await response.json();
          console.log("response.json():"+data);
          console.log(data);
          console.log("OK2");
          if (data.text) {
            this.recognitionResult = data.text;
          }
        } catch (err) {
          this.error = 'Failed to upload file';
          console.error(err);
        }
      };
      
      reader.readAsDataURL(file);
    }
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
}

.status-bar {
  margin-bottom: 20px;
  padding: 10px;
  border-radius: 4px;
  background: #f5f5f5;
  text-align: left;
}

.error-message {
  display: block;
  margin-top: 5px;
  color: #dc3545;
  font-size: 0.9em;
}

.mode-selector {
  margin: 20px 0;
}

button {
  padding: 10px 15px;
  margin: 0 10px;
  background: #42b983;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background 0.3s;
}

button:hover {
  background: #369f6b;
}

button:disabled {
  background: #cccccc;
  cursor: not-allowed;
}

.result-display {
  margin-top: 20px;
  padding: 15px;
  border: 1px solid #eee;
  border-radius: 4px;
  min-height: 100px;
  text-align: left;
  background: #f9f9f9;
}
</style>